/* $Id: ByteArray.java,v 1.1 2008/05/19 07:51:57 George Pogorelschi Exp $ */
/*
 * Copyright (C) 1996-2000 Mark R. Boyns <boyns@doit.org>
 *
 * This file is part of Muffin.
 *
 * Muffin is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Muffin is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Muffin; see the file COPYING.  If not, write to the
 * Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 */
package ro.qi.framework.sys.entities.components;

import java.io.IOException;
import java.io.OutputStream;

/**
 * Class used to represent an array of bytes as an Object.
 *
 * @author Mark Boyns
 */
public class ByteArray {

	private static final int INITIAL_SIZE			= 10240; // 10k
	private static final int EXTEND_SIZE			= 20480; // 20k

    public byte[] bytes;

    public int offset = 0;
    public int readOffset = 0;

    /**
     * Create a ByteArray with the default size.
     */
    public ByteArray() {
        this(INITIAL_SIZE);
    }

    /**
     * Create a ByteArray with a specific default size.
     *
     * @param size DOCUMENT ME!
     */
    public ByteArray(int size) {
        bytes = new byte[size];
    }

    /**
     * Create a ByteArray from a String.
     *
     * @param s DOCUMENT ME!
     */
    public ByteArray(String s) {
        this(s.length());
        append(s);
    }

    /**
     * Create a ByteArray from an array of bytes.
     *
     * @param b DOCUMENT ME!
     */
    public ByteArray(byte[] b) {
        this(b.length);
        append(b);
    }

    //~ Methods ----------------------------------------------------------------

	public byte byteAt(int index) {
		return bytes[index];
	}

	public char charAt(int index) {
		return (char)bytes[index];
	}
	
	public String readLine() {
		int idx = readOffset;
		while( bytes[idx] != 10 && idx < offset )
			idx ++;
		if( idx - readOffset == 0 )
			return "";
		idx ++;
		String line = new String(bytes, readOffset, idx - readOffset);
		readOffset = idx;
		return line;
	}

	public int read() {
		if( readOffset == offset )
			return - 1;
		byte b = bytes[readOffset++];
		if( b < 0 )
			return (int)(256 + b);
		return b;
	}

	public int indexOf(String str) {
		return indexOf(str, readOffset);
	}

	public int indexOf(String str, int startIndex) {
		int idx = startIndex;
		boolean found = false;
		while( idx < offset && !found ) {
			if(bytes[idx] == str.charAt(0)) {
				int strIndex = 0;
				while( strIndex < str.length() && strIndex < offset && bytes[idx + strIndex] == str.charAt(strIndex) ) {
					strIndex++;
				}
				if( strIndex == str.length() )
					found = true;
			}
			idx++;
		}
		if(found)
			return (idx-1);
		return -1;
	}

	public ByteArray getArray(int from, int to) {
		if( to < from )
			return null;
		if( to == from )
			return new ByteArray();
		byte[] b = new byte[to-from];
		System.arraycopy(bytes, from, b, 0, to-from);
		return new ByteArray(b);
	}

    /**
     * Append a byte.
     */
    public void append(byte ch) {
        if (offset == bytes.length) {
            byte[] tmpbytes = bytes;
            bytes = new byte[tmpbytes.length + EXTEND_SIZE];
            System.arraycopy(tmpbytes, 0, bytes, 0, tmpbytes.length);
        }
        bytes[offset++] = ch;
    }

    /**
     * Append a ByteArray.
     */
    public void append(ByteArray b) {
        if ((bytes.length - offset) < b.length()) {
            byte[] tmpbytes = bytes;
            bytes = new byte[tmpbytes.length + b.length() + EXTEND_SIZE];
            System.arraycopy(tmpbytes, 0, bytes, 0, offset);
        }
        System.arraycopy(b.bytes, 0, bytes, offset, b.length());
        offset += b.length();
    }

	/**
	 * Append an array of bytes.
	 */
	public void append(byte[] b) {
		if ((bytes.length - offset) < b.length) {
			byte[] tmpbytes = bytes;
			bytes = new byte[tmpbytes.length + b.length + EXTEND_SIZE];
			System.arraycopy(tmpbytes, 0, bytes, 0, offset);
		}
		System.arraycopy(b, 0, bytes, offset, b.length);
		offset += b.length;
	}

	/**
	 * Append an array of bytes.
	 */
	public void append(byte[] b, int size) {
		if ((bytes.length - offset) < size) {
			byte[] tmpbytes = bytes;
			bytes = new byte[tmpbytes.length + size + EXTEND_SIZE];
			System.arraycopy(tmpbytes, 0, bytes, 0, offset);
		}
		System.arraycopy(b, 0, bytes, offset, size);
		offset += size;
	}

	/**
	 * Append an array of bytes.
	 */
	public void append(byte[] b, int boffset, int size) {
		if ((bytes.length - offset) < size) {
			byte[] tmpbytes = bytes;
			bytes = new byte[tmpbytes.length + size + EXTEND_SIZE];
			System.arraycopy(tmpbytes, 0, bytes, 0, offset);
		}
		System.arraycopy(b, boffset, bytes, offset, size);
		offset += size;
	}

    /**
     * Append a String.
     */
    public void append(String s) {
        append(s.getBytes());
    }

    /**
     * Convert to String.
     */
    public String toString() {
        return new String(bytes, 0, offset);
    }

    /**
     * Return the bytes.
     */
    public byte[] getBytes() {
		byte[] filled = new byte[offset];
		System.arraycopy(bytes, 0, filled, 0, offset);
        return filled;
    }

	public int getSize() {
		return offset;
	}

    /**
     */
    public void writeTo(OutputStream out) throws IOException {
        out.write(bytes, 0, offset);
    }

    /**
     */
    public byte get(int i) {
        return bytes[i];
    }

    /**
     */
    public int length() {
        return offset;
    }

    /**
     */
    public void erase() {
        offset = 0;
    }

    /**
     */
    public void chop() {
        chop(1);
    }

    /**
     */
    public void chop(int i) {
        offset -= i;
        if (offset < 0) {
            offset = 0;
        }
    }

    public void cut(int i) {
    	if( i >= offset )
    		offset = 0;
    	else {
			offset -= i;
    		System.arraycopy(bytes, i, bytes, 0, offset);
    	}
    }

	public int remaining() {
		return bytes.length - offset;
	}

	public int position() {
		return readOffset;
	}

}
